#!/usr/bin/env php
<?php

use Swoole\Event;
use Swoole\Runtime;
use Yurun\Swoole\CoPool\CoPool;
use Yurun\Swoole\CoPool\Interfaces\ICoTask;
use Yurun\Swoole\CoPool\Interfaces\ITaskParam;

require dirname(__DIR__) . '/vendor/autoload.php';

/**
 * 开启服务器
 *
 * @return void
 */
function startServer()
{
    function checkMQTTServerStatus()
    {
        $serverStarted = false;
        for($i = 0; $i < 60; ++$i)
        {
            sleep(1);
            try {
                $sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
                if($sock && socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, array('sec' => 1, 'usec' => 0)) && @socket_connect($sock, '127.0.0.1', 8081))
                {
                    sleep(1);
                    $write = [$sock];
                    $read = $except = null;
                    if(socket_select($read, $write, $except, 1))
                    {
                        $serverStarted = true;
                        break;
                    }
                }
            } finally {
                socket_close($sock);
            }
        }
        return $serverStarted;
    }
    
    $dirname = dirname(__DIR__);
    $servers = [
        'MQTTServer'    =>  [
            'start'         => $dirname . '/example/bin/start-server.sh',
            'stop'          => $dirname . '/example/bin/stop-server.sh',
            'checkStatus'   => 'checkMQTTServerStatus',
        ],
    ];

    $pool = new CoPool(swoole_cpu_num(), 16,
        // 定义任务匿名类，当然你也可以定义成普通类，传入完整类名
        new class implements ICoTask
        {
            /**
             * 执行任务
             *
             * @param ITaskParam $param
             * @return mixed
             */
            public function run(ITaskParam $param)
            {
                ($param->getData())();
                // 执行任务
                return true; // 返回任务执行结果，非必须
            }

        }
    );
    $pool->run();

    $taskCount = count($servers);
    $completeTaskCount = 0;
    foreach($servers as $name => $options)
    {
        // 增加任务，异步回调
        $pool->addTaskAsync(function() use($options, $name){
            // start server
            $cmd = $options['start'];
            echo "Starting {$name}...", PHP_EOL;
            `{$cmd}`;

            register_shutdown_function(function() use($name, $options){
                // stop server
                $cmd = $options['stop'];
                echo "Stoping {$name}...", PHP_EOL;
                `{$cmd}`;
                echo "{$name} stoped!", PHP_EOL, PHP_EOL;
            });

            if(($options['checkStatus'])())
            {
                echo "{$name} started!", PHP_EOL;
            }
            else
            {
                throw new \RuntimeException("{$name} start failed");
            }
        }, function(ITaskParam $param, $data) use(&$completeTaskCount, $taskCount, $pool){
            // 异步回调
            ++$completeTaskCount;
        });
    }

    while($completeTaskCount < $taskCount)
    {
        usleep(10000);
    }
    $pool->stop();

}

function test()
{
    $descriptorspec = [
        ['pipe', 'r'],  // 标准输入，子进程从此管道中读取数据
        ['pipe', 'w'],  // 标准输出，子进程向此管道中写入数据
    ];
    $cmd = __DIR__ . '/phpunit -c ' . __DIR__ . '/phpunit.xml';
    $pipes = null;
    $processHndler = proc_open($cmd, $descriptorspec, $pipes);
    $records2 = [];
    while(!feof($pipes[1]))
    {
        $content = fgets($pipes[1]);
        if(false !== $content)
        {
            if(2 === count($records2))
            {
                array_shift($records2);
            }
            $records2[] = $content;
            echo $content;
        }
    }
    
    do {
        $status = proc_get_status($processHndler);
    } while($status['running'] ?? false);
    foreach($pipes as $pipe)
    {
        fclose($pipe);
    }
    proc_close($processHndler);
    
    if(version_compare(SWOOLE_VERSION, '4.4', '<') && 255 === ($status['exitcode'] ?? 0) && 'OK' === substr($records2[1] ?? '', 0, 2))
    {
        exit(0);
    }
    else
    {
        exit($status['exitcode'] ?? 0);
    }
}

register_shutdown_function(function(){
    echo 'Shutdown memory:', PHP_EOL, `free -m`, PHP_EOL;
});

echo 'Before start server memory:', PHP_EOL, `free -m`, PHP_EOL;
Runtime::enableCoroutine();
go('startServer');
Event::wait();
Runtime::enableCoroutine(false);
echo 'After start server memory:', PHP_EOL, `free -m`, PHP_EOL;
test();
